module IntQueue(
	
	input			i_IQ_clk,
	input			i_IQ_enable,
	input			i_IQ_reset,
	//Stall
	output			o_IQ_stall,
	input			i_IQ_IssueStall1,
	input			i_IQ_IssueStall2,
	//PhyRegState
	input	[63:0]	i_IQ_PhyRegState,
	//EnQueue
	input	[64:0]	i_IQ_VIP1,		//{[64]valid, [63:32]Inst, [31:0]PC}
	input	[11:0]	i_IQ_PRSrc1,	//{[11:6]pregsrc1, [5:0]pregsrc2}
	input	[16:0]	i_IQ_PRDes1,	//{[16:12]regdes, [11:6]pregdes, [5:0]ppregdes}
	input	[29:0]	i_IQ_IDcode1,	//{[29:25]alcode, [24:20]bjcode, [19:15]iecode, [14:10]mvcode, [9:5]mdcode, [4:0]memcode}			
	input	[33:0]	i_IQ_BranchTT1,	//{[33:32]BranchTaken, [31:0]BranchTarget}
	input	[7:0]	i_IQ_EXCCODE1,
	input	[5:0]	i_IQ_ReOrderNum1,
	input	[64:0]	i_IQ_VIP2,		
	input	[11:0]	i_IQ_PRSrc2,	
	input	[16:0]	i_IQ_PRDes2,	
	input	[29:0]	i_IQ_IDcode2,
	input	[33:0]	i_IQ_BranchTT2,	
	input	[7:0]	i_IQ_EXCCODE2,
	input	[5:0]	i_IQ_ReOrderNum2,
	//DeQueue
	output	[64:0]	o_IQ_VIP1,		//{[64]valid, [63:32]Inst, [31:0]PC}
	output	[11:0]	o_IQ_PRSrc1,	//{[11:6]pregsrc1, [5:0]pregsrc2}
	output	[16:0]	o_IQ_PRDes1,	//{[16:12]regdes, [11:6]pregdes, [5:0]ppregdes}
	output	[29:0]	o_IQ_IDcode1,	//{[29:25]alcode, [24:20]bjcode, [19:15]iecode, [14:10]mvcode, [9:5]mdcode, [4:0]memcode}			
	output	[33:0]	o_IQ_BranchTT1,	//{[33:32]BranchTaken, [31:0]BranchTarget}
	output	[7:0]	o_IQ_EXCCODE1,
	output	[5:0]	o_IQ_ReOrderNum1,
	output	[64:0]	o_IQ_VIP2,
	output	[11:0]	o_IQ_PRSrc2,	
	output	[16:0]	o_IQ_PRDes2,	
	output	[29:0]	o_IQ_IDcode2,
	output	[33:0]	o_IQ_BranchTT2,
	output	[7:0]	o_IQ_EXCCODE2,
	output	[5:0]	o_IQ_ReOrderNum2,
	//COMMIT
	input			I_IQ_CMTrollback

);

	reg			valid[15:0]
	reg	[5:0]	pregrc1[15:0];
	reg	[5:0]	pregrc2[15:0];
	//follow
	reg	[63:0]	InstPC[15:0];
	reg	[16:0]	PRDes[15:0];
	reg	[29:0]	IDcode[15:0];
	reg	[33:0]	BranchTT[15:0];
	reg	[7:0]	EXCCODE[15:0];
	reg	[5:0]	ReOrderNum[15:0];
	
	/*	
		Calculate EnQueuePointer	
	*/
	wire	[15:0]	EmptyList;
	begin:	emptylist
		reg	[7:0]	tempI;
		for(tempI=8'd1; tempI<=8'd15; tempI=tempI+8'd1)
			assign	EmptyList[tempI[3:0]] = ~valid[tempI[3:0]];
	end
	assign	EmptyList[0] = 1'd0;

	wire	[15:0]	EL_lowbit = (~EmptyList+16'd1) & EmptyList;
	wire	[15:0]	EL_secbit = (~(EmptyList-EL_lowbit) + 16'd1) & (EmptyList-EL_lowbit);

	wire	[3:0]	EnQueuePointer1;
	wire	[3:0]	EnQueuePointer2;
LeadingOneCount16 IQ_LOC16_EnQueuePointer1(
	.i_LOC16_datain(EL_lowbit),
	.o_LOC16_vld(	),
	.o_LOC16_cnt(	EnQueuePointer1)
);
LeadingOneCount16 IQ_LOC16_EnQueuePointer2(
	.i_LOC16_datain(EL_secbit),
	.o_LOC16_vld(	),
	.o_LOC16_cnt(	EnQueuePointer2)
);

	wire	match1 = i_IQ_VIP1[64] && (i_IQ_IDcode1[29:15]!=15'd0);
	wire	match2 = i_IQ_VIP2[64] && (i_IQ_IDcode2[29:15]!=15'd0);
	
	assign o_IQ_stall = (EmptyList==16'd0 && (match1 || match2)) ||
						(EL_secbit==16'd0 && match1 && match2)
	
	/*	
		Calculate DeQueuePointer	
	*/
	wire	[15:0]	ReadyList;
	begin:	readylist
		reg [7:0]	tempJ;
		for(tempJ=8'd1; tempJ<=8'd15; tempJ=tempJ+8'd1)
			assign	ReadyList[tempJ[3:0]] = valid[tempJ[3:0]] && 
											i_IQ_PhyRegState[pregrc1[tempJ[3:0]]] &&
											i_IQ_PhyRegState[pregrc2[tempJ[3:0]]];
	end
	assign	ReadyList[0] = 1'b0;
	
	wire	[15:0]	RL_lowbit = (~ReadyList+16'd1) & ReadyList;
	wire	[15:0]	RL_secbit = (~(ReadyList-RL_lowbit) + 16'd1) & (ReadyList-RL_lowbit);
	
	wire	[3:0]	DeQueuePointer1;
	wire	[3:0]	DeQueuePointer2;
	assign	o_IQ_VIP1		 = {valid[DeQueuePointer1], InstPC[DeQueuePointer1]};
	assign	o_IQ_PRSrc1		 = {pregrc1[DeQueuePointer1], pregrc2[DeQueuePointer1]};
	assign	o_IQ_PRDes1		 = PRDes[DeQueuePointer1];
	assign	o_IQ_IDcode1	 = IDcode[DeQueuePointer1];
	assign	o_IQ_BranchTT1	 = BranchTT[DeQueuePointer1];
	assign	o_IQ_EXCCODE1	 = EXCCODE[DeQueuePointer1];
	assign	o_IQ_ReOrderNum1 = ReOrderNum[DeQueuePointer1];
	assign	o_IQ_VIP2		 = {valid[DeQueuePointer2], InstPC[DeQueuePointer2]};
	assign	o_IQ_PRSrc2		 = {pregrc1[DeQueuePointer2], pregrc2[DeQueuePointer2]};
	assign	o_IQ_PRDes2		 = PRDes[DeQueuePointer2];
	assign	o_IQ_IDcode2	 = IDcode[DeQueuePointer2];
	assign	o_IQ_BranchTT2	 = BranchTT[DeQueuePointer2];
	assign	o_IQ_EXCCODE2	 = EXCCODE[DeQueuePointer2];
	assign	o_IQ_ReOrderNum2 = ReOrderNum[DeQueuePointer2];
	
LeadingOneCount16 IQ_LOC16_DeQueuePointer1(
	.i_LOC16_datain(RL_lowbit),
	.o_LOC16_vld(	),
	.o_LOC16_cnt(	DeQueuePointer1)
);
LeadingOneCount16 IQ_LOC16_DeQueuePointer2(
	.i_LOC16_datain(RL_secbit),
	.o_LOC16_vld(	),
	.o_LOC16_cnt(	DeQueuePointer2)
);
	
always @(posedge i_IQ_clk)
	begin
		if(i_IQ_reset)
			begin:	reset
				reg	[7:0]	tempK;
				for(tempK=8'd0; tempK<=8'd15; tempK=tempK+8'd1)
					begin
						valid[tempK[3:0]]		<= 1'd0;
						pregrc1[tempK[3:0]]		<= 6'd0;
						pregrc2[tempK[3:0]]		<= 6'd0;
						//follow
						InstPC[tempK[3:0]]		<= 64'd0;
						PRDes[tempK[3:0]]		<= 17'd0;
						IDcode[tempK[3:0]]		<= 30'd0;
						BranchTT[tempK[3:0]]	<= 34'd0;
						EXCCODE[tempK[3:0]]		<= 8'd0;
						ReOrderNum[tempK[3:0]]	<= 6'd0;
					end
			end
		else if(i_IQ_enable)
			begin
				if(I_IQ_CMTrollback)
					begin
						//rollback
						reg	[7:0]	tempL;
						for(tempL=8'd0; tempL<=8'd15; tempL=tempL+8'd1)
							begin
							valid[tempL[3:0]]		<= 1'd0;
							pregrc1[tempL[3:0]]		<= 6'd0;
							pregrc2[tempL[3:0]]		<= 6'd0;
							//follow
							InstPC[tempL[3:0]]		<= 64'd0;
							PRDes[tempL[3:0]]		<= 17'd0;
							IDcode[tempL[3:0]]		<= 30'd0;
							BranchTT[tempL[3:0]]	<= 34'd0;
							EXCCODE[tempL[3:0]]		<= 8'd0;
							ReOrderNum[tempL[3:0]]	<= 6'd0;
						end
					end
				else
					begin
						//EnQueue
						if(~o_IQ_stall && match1 && match2)
							begin
								valid[EnQueuePointer1]		<= i_IQ_VIP1[64];
								pregrc1[EnQueuePointer1]	<= i_IQ_PRSrc1[11:6];
								pregrc2[EnQueuePointer1]	<= i_IQ_PRSrc1[5:0];
								InstPC[EnQueuePointer1]		<= i_IQ_VIP1[63:0];
								PRDes[EnQueuePointer1]		<= i_IQ_PRDes1;
								IDcode[EnQueuePointer1]		<= i_IQ_IDcode1;
								BranchTT[EnQueuePointer1]	<= i_IQ_BranchTT1;
								EXCCODE[EnQueuePointer1]	<= i_IQ_EXCCODE1;
								ReOrderNum[EnQueuePointer1]	<= i_IQ_ReOrderNum1;
								
								valid[EnQueuePointer2]		<= i_IQ_VIP2[64];
								pregrc1[EnQueuePointer2]	<= i_IQ_PRSrc2[11:6];
								pregrc2[EnQueuePointer2]	<= i_IQ_PRSrc2[5:0];
								InstPC[EnQueuePointer2]		<= i_IQ_VIP2[63:0];
								PRDes[EnQueuePointer2]		<= i_IQ_PRDes2;
								IDcode[EnQueuePointer2]		<= i_IQ_IDcode2;
								BranchTT[EnQueuePointer2]	<= i_IQ_BranchTT2;
								EXCCODE[EnQueuePointer2]	<= i_IQ_EXCCODE2;
								ReOrderNum[EnQueuePointer2]	<= i_IQ_ReOrderNum2;
							end
						if(~o_IQ_stall && match1 && ~match2)
							begin
								valid[EnQueuePointer1]		<= i_IQ_VIP1[64];
								pregrc1[EnQueuePointer1]	<= i_IQ_PRSrc1[11:6];
								pregrc2[EnQueuePointer1]	<= i_IQ_PRSrc1[5:0];
								InstPC[EnQueuePointer1]		<= i_IQ_VIP1[63:0];
								PRDes[EnQueuePointer1]		<= i_IQ_PRDes1;
								IDcode[EnQueuePointer1]		<= i_IQ_IDcode1;
								BranchTT[EnQueuePointer1]	<= i_IQ_BranchTT1;
								EXCCODE[EnQueuePointer1]	<= i_IQ_EXCCODE1;
								ReOrderNum[EnQueuePointer1]	<= i_IQ_ReOrderNum1;
							end
						if(~o_IQ_stall && ~match1 && match2)
							begin
								valid[EnQueuePointer2]		<= i_IQ_VIP2[64];
								pregrc1[EnQueuePointer2]	<= i_IQ_PRSrc2[11:6];
								pregrc2[EnQueuePointer2]	<= i_IQ_PRSrc2[5:0];
								InstPC[EnQueuePointer2]		<= i_IQ_VIP2[63:0];
								PRDes[EnQueuePointer2]		<= i_IQ_PRDes2;
								IDcode[EnQueuePointer2]		<= i_IQ_IDcode2;
								BranchTT[EnQueuePointer2]	<= i_IQ_BranchTT2;
								EXCCODE[EnQueuePointer2]	<= i_IQ_EXCCODE2;
								ReOrderNum[EnQueuePointer2]	<= i_IQ_ReOrderNum2;
							end
						//DeQueue
						if(~i_IQ_IssueStall1)
							begin
								valid[DeQueuePointer1]		<= 1'd0;
								pregrc1[DeQueuePointer1]	<= 6'd0;
								pregrc2[DeQueuePointer1]	<= 6'd0;
								InstPC[DeQueuePointer1]		<= 64'd0;
								PRDes[DeQueuePointer1]		<= 17'd0;
								IDcode[DeQueuePointer1]		<= 30'd0;
								BranchTT[DeQueuePointer1]	<= 34'd0;
								EXCCODE[DeQueuePointer1]	<= 8'd0;
								ReOrderNum[DeQueuePointer1]	<= 6'd0;
							end
						if(~i_IQ_IssueStall1)
							begin
								valid[DeQueuePointer2]		<= 1'd0;
								pregrc1[DeQueuePointer2]	<= 6'd0;
								pregrc2[DeQueuePointer2]	<= 6'd0;
								InstPC[DeQueuePointer2]		<= 64'd0;
								PRDes[DeQueuePointer2]		<= 17'd0;
								IDcode[DeQueuePointer2]		<= 30'd0;
								BranchTT[DeQueuePointer2]	<= 34'd0;
								EXCCODE[DeQueuePointer2]	<= 8'd0;
								ReOrderNum[DeQueuePointer2]	<= 6'd0;
							end
					end
			end
	end

endmodule